BZOJ2002 Bounce 弹飞绵羊 <分块>

Problem

Bounce 弹飞绵羊

Description

某天, 发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始, 在地上沿着一条直线摆上 个装置,每个装置设定初始弹力系数 ,当绵羊达到第 个装置时,它会往后弹 步,达到第 个装置,若不存在第 个装置,则绵羊被弹飞。绵羊想知道当它从第 个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣, 可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。

Input

第一行包含一个整数 ,表示地上有 个装置,装置的编号从 ,接下来一行有 个正整数,依次为那 个装置的初始弹力系数。第三行有一个正整数 ,接下来 行每行至少有两个数 ,若 ,你要输出从 出发被弹几次后被弹飞,若 则还会再输入一个正整数 ,表示第 个弹力装置的系数被修改成

Output

对于每个 的情况,你都要输出一个需要的步数,占一行。

Sample Input

1
2
3
4
5
6
4 
1 2 1 1
3
1 1
2 1 1
1 1

Sample Output

1
2
2
3

Hint

对于 的数据
对于 的数据 ,

标签:LCT 分块

Solution

本题其实应该是 的基础题,但是因为我身为蒟蒻写不来 ,就用分块做了。
把原数列分为 个块,对于每个块,维护块内的每个位置需要多少步才能跳到块外,以及跳到块外后的位置,对于修改操作,重算那个块内的所有位置的两个值,这样单次询问或修改复杂度 ,总复杂度 。可过。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <cstdio>
#include <cmath>
#define MAX_N 200000
using namespace std;
int n, m, magic, k[MAX_N+5];
int pos[MAX_N+5], times[MAX_N+5];
void update(int l, int r) {
for (int i = r; i >= l; i--)
if (i+k[i] >= n) pos[i] = -1, times[i] = 1;
else if (i+k[i] >= (i/magic+1)*magic) pos[i] = i+k[i], times[i] = 1;
else pos[i] = pos[i+k[i]], times[i] = times[i+k[i]]+1;
}
int main() {
scanf("%d", &n), magic = sqrt(n);
for (int i = 0; i < n; i++) scanf("%d", &k[i]); update(0, n-1);
scanf("%d", &m);
while (m--) {
int opt; scanf("%d", &opt);
if (opt == 1) {
int x, ans = 0;
scanf("%d", &x);
while (x != -1) ans += times[x], x = pos[x];
printf("%d\n", ans);
}
if (opt == 2) {int x, y; scanf("%d%d", &x, &y), k[x] = y; update(x/magic*magic, x);}
}
return 0;
}
------------- Thanks For Reading -------------
0%